package com.cskaoyan.javase.oop2._2polymorphic._2advantage;

/**
 * @description: 多态的优缺点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * > 引例
 * - 科学家要收集动物的叫声去研究
 * - 定义猫，狗实际动物类，它们都会叫
 * - 定义收集猫、狗叫声的方法
 * - 要收集猪的声音，怎么办呢
 *
 * 每收集一个动物叫声都需要写一个方法,显然过于麻烦,思考能不能合在一个方法当中?
 * 这里就要使用多态方法调用的特点了: 编译时看左边,运行时看右边
 * 只需要方法形参中写Animal引用,父类引用可以指向不同的子类对象,并且它们的行为仍然是对象的行为
 *
 * 当方法的形参中写一个父类类型时,可以传入它的对象,也可以传入子类对象(因为子类可以看成父类/自动类型转换)
 * 同样的,方法的返回值也可以这么写
 *
 * 新需求:
 *      现在科学家把除人类的动物都研究了,要开始研究人类了
 *      人毕竟是人,和动物不同.人是抓不来,需要请过来协助
 *      所以人请来需要花钱,需要加钱
 *      人有额外的行为,叫"加钱"
 *
 * 如果想要用Animal引用访问加钱方法是做不到的,需要先完成强制类型转换
 *
 * 引用数据类型的强制类型转换:
 *      1,条件: 必须把父类引用转换成子类引用,如果转换的引用没有父类关系,会编译报错
 *      2,即便是编译不报错,要想强转成功也需要一定的限制,如果想要成功转换,条件只有一个:
 *       你要强转的那个父类引用指向的对象,必须是强转后引用的真实对象(如果是别的子类,肯定强转失败,但是不会编译报错)
 *      3,强转如果失败,会抛出异常ClassCastException,类型转换异常,这个异常发生在当你想把一个错误的对象转换成相应子类引用时
 *      4,引用数据类型强制类型转换是很危险的,很容易导致程序报错终止,所以我们在做强转之前应该先进行检查,检查无误后再做强转
 *      5,检查的手段:
 *      对象名 instanceof 类名
 *      表示检查前面对象名/引用指向的对象是否是后面类名的真实对象或者子类对象
 *      推荐在不确定类型时,做强转永远先检查
 *
 *
 * 总结多态的优点:
 *      1,既然有多态就有继承,代码复用,减少代码冗余
 *      2,使用多态的方式让程序更加简洁,程序的扩展性也提升了,可维护性就提升了
 * 多态的缺点:
 *      因为需要父类引用指向子类对象,父类引用就无法访问子类独有的成员了
 *
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        Cat c = new Cat();
        Dog d = new Dog();
        collectVoice(d); //Animal a = new Dog();
        collectVoice(c); //Animal a = new Cat();
       collectVoice(new Pig());

        Person p = new Person();
        collectVoice(p);
    }

    /*//收集猫的叫声并研究的方法
    public static void collectVoice(Cat c){
        //抓一只猫过来
        c.shout();
        //收集研究
    }

    //收集狗的叫声并研究的方法
    public static void collectVoice(Dog d){
        //抓一只狗过来
        d.shout();
        //收集研究
    }*/

    public static void collectVoice(Animal a){
        //如果是人,需要先加钱再叫
        //这时候引用是父类的,限制了访问范围,为了突破限制,需要把引用的类型再转换成子类类型
        //这种类型转换,方向是: 父类 --> 子类 叫向下转型,也叫强制类型转换
        //使用instanceof判断,只有是人对象时,才做强转
        if (a instanceof Person){
            //a指向的对象是Person对象/子类对象
            Person p = (Person) a;
            p.addMoney();
        }
        /*Person p = (Person) a;
        p.addMoney();*/
        //抓一只动物来
        a.shout();
        //收集研究
    }
}
class Animal{
    String name;
    int age;

    public void shout(){
        System.out.println("叫了一声");
    }
}
class Cat extends Animal{
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}
class Dog extends Animal{
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
}
class Pig extends Animal{
    @Override
    public void shout() {
        System.out.println("呵呵呵!");
    }
}
class Person extends Animal{
    @Override
    public void shout() {
        System.out.println("嗷嗷嗷");
    }
    //额外的方法,行为---加钱
    public void addMoney(){
        System.out.println("给加钱,我就叫!");
    }
}